package win.bigwhale.sudoku.logic;

import java.awt.Point;
import java.util.ArrayList;

import win.bigwhale.sudoku.controller.GameController;

public class SudokuMatrix {
	private static SudokuMatrix sudokuMatrix = new SudokuMatrix();
	private SudokuMap sudokuMap = SudokuMap.getSudokuMap();
	
	private NumberGroup[] rows = null;
	private NumberGroup[] columns = null;
	private NumberGroup[] rects = null;
	private NumberGroup[] numberGroups = null;
	
	private SudokuMatrix() {
		initialMatrix();
	}
	
	public static SudokuMatrix getSudokuMatrix() {
		return sudokuMatrix;
	}

	private void initialMatrix() {
		rows = new NumberGroup[9];
		columns = new NumberGroup[9];
		rects = new NumberGroup[9];
		numberGroups = new NumberGroup[9];
		
		for (int i = 0; i < rows.length; i++) {
			rows[i] = new NumberGroup();
			columns[i] = new NumberGroup();
			rects[i] = new NumberGroup();
			numberGroups[i] = new NumberGroup();
		}
	}
	
	public void addSudokuNumber(SudokuNumber sudokuNumber) {
		if (!isValidSudokuNumber(sudokuNumber)) {
			return;
		}

		doAddNum(sudokuNumber);
		if (isGameCompleted()) {
			System.out.println("Completed");
			GameController.getGameController().completeGame();
		}
	}

	private boolean isValidSudokuNumber(SudokuNumber sudokuNumber) {
		if (!rows[sudokuNumber.getRow()].isValid(sudokuNumber)) {
			return false;
		}
		if (!columns[sudokuNumber.getColumn()].isValid(sudokuNumber)) {
			return false;
		}
		if (!rects[sudokuNumber.getRect()].isValid(sudokuNumber)) {
			return false;
		}
		return deleteInputedNumber(sudokuNumber.getNumberPosition());
	}

	public boolean deleteInputedNumber(Point point) {
		if (!sudokuMap.isValid(point)) {
			if (sudokuMap.getSudokuNumber(point).isOrig()) {
				return false;
			}
			doRemoveNum(sudokuMap.getSudokuNumber(point));
		}
		return true;
	}

	public boolean isOriginNumberPosition(Point selectedPosition) {
		if (sudokuMap.getSudokuNumber(selectedPosition) != null
				&& sudokuMap.getSudokuNumber(selectedPosition).isOrig()) {
			return true;
		}
		return false;
	}

	public boolean isGameCompleted() {
		if (sudokuMap.isFull()) {
			return true;
		}
		return false;
	}

	public void removeAllNum() {
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (sudokuMap.isValid(i, j)) {
					continue;
				}
				doRemoveNum(sudokuMap.getSudokuNumber(i, j));
			}
		}
	}

	private void doRemoveNum(SudokuNumber sudokuNumber) {
		rows[sudokuNumber.getRow()].removeNumber(sudokuNumber);
		columns[sudokuNumber.getColumn()].removeNumber(sudokuNumber);
		rects[sudokuNumber.getRect()].removeNumber(sudokuNumber);
		numberGroups[sudokuNumber.getNumber() - 1].removeNumber(sudokuNumber);
		numberGroups[sudokuNumber.getNumber() - 1].setBackColor();
		sudokuNumber.removeSelf();
		sudokuMap.setValid(sudokuNumber.getNumberPosition(), null);
	}

	private void doAddNum(SudokuNumber sudokuNumber) {
		sudokuNumber.createNumText();
		rows[sudokuNumber.getRow()].add(sudokuNumber);
		columns[sudokuNumber.getColumn()].add(sudokuNumber);
		rects[sudokuNumber.getRect()].add(sudokuNumber);
		sudokuMap.setValid(sudokuNumber.getColumn(), sudokuNumber.getRow(), sudokuNumber);
		numberGroups[sudokuNumber.getNumber() - 1].add(sudokuNumber);
		numberGroups[sudokuNumber.getNumber() - 1].setFinishedColor();
		sudokuNumber.addSelf();
	}

	public void setNumberVisible(boolean visible) {
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (sudokuMap.isValid(i, j)) {
					continue;
				}
				sudokuMap.getSudokuNumber(i, j).setVisible(visible);
			}
		}
	}

	public ArrayList<SudokuNumber> getSudokuNumbers() {
		ArrayList<SudokuNumber> numbers = new ArrayList<>();
		for (int i = 0; i < 9; i++) {
			for (int j = 0; j < 9; j++) {
				if (sudokuMap.isValid(i, j)) {
					continue;
				}
				numbers.add(sudokuMap.getSudokuNumber(i, j));
			}
		}

		return numbers;
	}
}
